<?php

class ELException extends Exception {
	public function __construct( $message ) {
		parent::__construct( $message );
	}
	
}


class VariableMapper {
	
	public function __constrct( ELContext $context ) {
		
	}
	
	public function resolveVariable( $variable ) {
		
	}
	
	public function setVariable( $variable, ValueExpression $expression ) {
		
	}
}

class ELContext {
	private $contexts;
	private $elResolver;
	
	public function __construct() {
		$this->elResolver = new ELResolver();
	}
	
	public function putContext( $key, &$context ) {
		$this->contexts[ $key ] = $context;
	}
	
	public function &getContext( $key ) {
		return $this->contexts[ $key ];
	}
	
	// this is not in the spec
	public function getContextNames() {
		return array_keys( $this->contexts );
	}
	
	public function getVariableMapper() {
		return new VariableMapper( $this );
	}
	
	public function getELResolver() {
		return $this->elResolver;
	}
	
}

class ELResolver {
	
	public function getType( ELContext $context, $expression ) {
		$value = $this->getValue( $context, $expression );
		return get_class( $value );
	}
	
	public function getValue( ELContext $context, $expression ) {

		$expressionParts = split( "\.", $expression );
		
		foreach( $context->getContextNames() as $contextName ) {
			$ref =& $context->getContext( $contextName );
			
			$isCallable = false;
			$isAccessor = false;
			$isReadOnly = true;
			
			for( $i = 0; $i < count($expressionParts); $i++ ) {
				$partName = $expressionParts[$i];  
				if( is_array( $ref ) && array_key_exists( $partName, $ref ) ) {
					$ref =& $ref[$partName];
					$isCallable = false;
					$isAccessor = false;
					$isReadOnly = false;
				} else if( is_object( $ref ) && property_exists( $ref, $partName ) ) {
					$ref =& $ref->$partName;
					$isCallable = false;
					$isAccessor = false;
					$isReadOnly = false;
				} else if( is_object( $ref ) && method_exists( $ref, "get".$partName ) ) {
					$accessor = "get".$partName;
					$ref =& $ref->$accessor();
					$isCallable = false;
					$isAccessor = true;
					$isReadOnly = !method_exists( $ref, "set".$partName );
				} else if( is_object( $ref ) && method_exists( $ref, $partName ) ) {	
					$actionRef = array( &$ref, $partName);
					$ref =& $actionRef;
					$isCallable = true;
					$isAccessor = false;
					$isReadOnly = true;
				} else {
					throw new PhpFaces_VariableNotFoundException( $elFragment );
				}
			}
			
			if( $ref != null ) {
				// TODO use properties we got about it
				return $ref;
			}
			
			
			unset( $ref );
		}
	}
	
	public function isReadOnly() {
		
	}
	
	protected function getExpressionBase( $expression ) {
		$parts = split( '.', $expression ) ;
		return $parts[0];
	}
	
	protected static function resolveFromContext( $elFragment, &$context ) {

	}
	
	
}

/**
 * http://java.sun.com/javaee/5/docs/api/javax/el/Expression.html
 */
class Expression {
	
	protected $expression;
	
	public function __construct( $expression ) {
		$this->expression = $expression;
	}
	
	public function getExpressionString() {
		return $this->expression;
	}

	public function isLiteralText() {
		
	}
}

/**
 * http://java.sun.com/javaee/5/docs/api/javax/el/ValueExpression.html
 */
class ValueExpression extends Expression {

	protected $expectedType;
	
	public function __construct( $expression, $expectedType ) {
		parent::__construct( $expression );
	}
	public function getValue( ELContext $context ) {
		$resolver = $context->getELResolver();
		
		
	}
	
	public function setValue( ELContext $context, $value ) {
		
	}
	
	public function isReadOnly( ELContext $context ) {
		
	}
	
	public function getType( ELContext $context ) {
		
	}
	
	public function getExprectedType( ELContext $context ) {
		return $this->expectedType;
	}
}


class MethodExpression extends Expression {
	public function getMethodInfo( &$context ) {
		
	}
	
	public function invoke( &$context, $params ) {
		
	}
}

class ExpressionFactory {
	public static function createValueExpression( &$context, $expression, $expectedType = null ) {
		$context->get
	}
	
}

?>